/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package model;

import bllobjects.Account;
import chat.ChatMessage;
import chat.CommandMessage;
import chat.IChatMessageListener;
import chat.SoundChatMessage;
import chat.TextChatMessage;
import chat.sound.SoundChatManager;
import fsktms.request.IRequestDelegate;
import fsktms.request.Request;
import fsktms.request.RequestParameters;
import fsktms.request.RequestRespond;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import model.chat.ChatMessageModel;
import qclient.QClient;
import tbquestion_client.form.ClientForms;

/**
 *
 * @author salm
 */
public class ClientModel implements IChatMessageListener
{
    private ClientModel()
    {
    }
    
    public static synchronized ClientModel getInstance() {
        return inst;
    }
    private static ClientModel inst = new ClientModel();
    
    private Account account;
    private FriendRequestsModel friendRequestsModel= new FriendRequestsModel();
    private FriendListModel friendList = new FriendListModel();
    private Map<String, ChatMessageModel> messageModels = new HashMap();
    private Map<String, FriendListModel> roomUsers = new HashMap();
    private ClientForms forms = new ClientForms();
    private SoundChatManager soundChatManager = new SoundChatManager();

    /**
     * @return the account
     */
    public Account getAccount() {
        return account;
    }

    /**
     * @param account the account to set
     */
    public void setAccount(Account account) {
        this.account = account;
        this.loadFriendList();
        this.loginToChatServer();
    }
    
    private void loginToChatServer()
    {
        ObjectOutputStream oos = null;
        try {
            CommandMessage loginMsg = new CommandMessage(this.account.getUserID(),
                    null, CommandMessage.COMMANDMESSAGE_TYPE_USER_JOINED, null);
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(bos);
            oos.writeObject(loginMsg);
            QClient.getInstance().getNetClient().sendMessage(bos.toByteArray(),
                    ChatMessage.CHAT_MESSAGE_MAGICKEY);
        } catch (IOException ex) {
            Logger.getLogger(ClientModel.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                oos.close();
            } catch (IOException ex) {
                Logger.getLogger(ClientModel.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
    
    public void loadFriendList()
    {
        try 
        {
            RequestParameters params = new RequestParameters()
                    .set(RequestParameters.KEY_FUNCTION, "getFriendList")
                    .set("Name", ClientModel.getInstance().getAccount().getUserID());
            final ClientModel thisCopy = this;
            QClient.getInstance().getRequestManager().sendRequest(
                    new Request("Relation", params, new IRequestDelegate() {

                @Override
                public void requestCompleted(RequestRespond respond) {
                    if (respond.isSuccess())
                    {
                        thisCopy.friendList.addAccounts((Collection<Account>)respond.getResult());
                    }
                }
            }));
        } 
        catch (IOException ex) {
            Logger.getLogger(ClientModel.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * @return the requestsModel
     */
    public FriendRequestsModel getRequestsModel() {
        return friendRequestsModel;
    }

    /**
     * @return the friendList
     */
    public FriendListModel getFriendList() {
        return friendList;
    }

    /**
     * @return the messageModels
     */
    public Map<String, ChatMessageModel> getMessageModels() {
        return messageModels;
    }

    @Override
    public void onHasChatMessage(ChatMessage chatMsg)
    {
        if (chatMsg instanceof TextChatMessage)
        {
            String modelID = chatMsg.getReceiverID();
            if (modelID.equals(this.account.getUserID()))
            {
                modelID = chatMsg.getSenderID();
            }
            
            if (!this.messageModels.containsKey(modelID))
            {
                this.messageModels.put(modelID, new ChatMessageModel());
            }
            
            ChatMessageModel chatMsgModel = this.messageModels.get(modelID);
            if (!chatMsg.getSenderID().equals(this.account.getUserID()))
            {
                chatMsgModel.addMessage((TextChatMessage) chatMsg);
            }
        }
        if (chatMsg instanceof SoundChatMessage)
        {
            SoundChatMessage soundChatMsg = (SoundChatMessage) chatMsg;
            String ownerID = chatMsg.getReceiverID();
            if (ownerID.equals(this.account.getUserID()))
            {
                ownerID = chatMsg.getSenderID();
            }
            if (!soundChatMsg.getSenderID().equals(this.account.getUserID()))
            {
                this.soundChatManager.onReceiverSound(ownerID,
                        soundChatMsg.getSoundData());
            }
        }
        else if (chatMsg instanceof CommandMessage)
        {
            final CommandMessage commandMsg = (CommandMessage) chatMsg;
            String roomID = chatMsg.getSenderID();
            if (commandMsg.getCommandType() == CommandMessage.COMMANDMESSAGE_TYPE_BECOME_TALKER)
            {
                this.soundChatManager.notifyToTalker(roomID);
                return;
            }
            
            String commandUser = commandMsg.getCommandParam();
            final FriendListModel frListModel = this.roomUsers.get(roomID);
            if (frListModel == null || commandUser.equals(this.account.getUserID()))
                return;
             
            try 
            {
                RequestParameters params = new RequestParameters()
                        .set(RequestParameters.KEY_FUNCTION, "getAccountInfo")
                        .set("ID", commandUser);
                final ClientModel thisCopy = this;
                QClient.getInstance().getRequestManager().sendRequest(
                        new Request("Account", params, new IRequestDelegate() {

                    @Override
                    public void requestCompleted(RequestRespond respond) {
                        if (respond.isFailed())
                            return;
                        Account friend = (Account) respond.getResult();
                        switch (commandMsg.getCommandType())
                        {
                            case CommandMessage.COMMANDMESSAGE_TYPE_USER_JOINED:
                            case CommandMessage.COMMANDMESSAGE_TYPE_USER_CHANGED:
                                frListModel.addAccount(friend);
                                break;
                            case CommandMessage.COMMANDMESSAGE_TYPE_USER_LEFT:
                                frListModel.removeAccount(friend);
                                break;
                            default:
                                break;
                        }
                    }
                }));
            } 
            catch (IOException ex) {
                Logger.getLogger(ClientModel.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    /**
     * @return the forms
     */
    public ClientForms getForms() {
        return forms;
    }

    /**
     * @return the roomUsers
     */
    public Map<String, FriendListModel> getRoomUsers() {
        return roomUsers;
    }

    /**
     * @return the soundChatManager
     */
    public SoundChatManager getSoundChatManager() {
        return soundChatManager;
    }
    
    public static void clear()
    {
        ClientModel.inst.forms.disposeAll();
        ClientModel.inst = new ClientModel();
    }
}
